function Foo() {
  getName = function () {
    console.log(1)
  };
  return this;
}
Foo.getName = function () {
  console.log(2)
};
Foo.prototype.getName = function () {
  console.log(3)
};
var getName = function () {
  console.log(4)
};
function getName() {
  console.log(5)
}

//请写出以下输出结果：
Foo.getName();  // 2
getName();  // 4
Foo().getName();  // 1
getName(); // 1
new Foo.getName(); // 2
new Foo().getName();  // 3
new new Foo().getName();  // 3

/**
 * 
 * 解析如下：
 * 首先定义了一个叫Foo的函数，之后为Foo创建了一个叫getName的静态属性存储了一个匿名函数，
 * 之后为Foo的原型对象新创建了一个叫getName的匿名函数。之后又通过函数变量表达式创建了一个getName的函数，
 * 最后再声明一个叫getName函数。
 * 
 * 1、Foo.getName() ----- 2
 * 
 * 第一问的 Foo.getName 自然是访问Foo函数上存储的静态属性，自然是2，没什么可说的。
 * 
 * 2、getName(); ------- 4
 * 
 * 直接调用 getName 函数。既然是直接调用那么就是访问当前上文作用域内的叫getName的函数，所以跟1 2 3都没什么关系。
 * 此题有无数面试者回答为5。此处有两个坑，一是变量声明提升，二是函数表达式。
 * 
 * 解析：：：
 * function Foo() { ······ }
 * 变量提升
 * var getName
 * 函数提升
 * function getName() {
 *   console.log(5)
 * }
 * .
 * .
 * .
 * .
 * getName = function () {
 *  console.log(4)
 * }
 * 最终执行getName()的是getName = function() {console.log(4)}  输出4
 * 
 * 
 * 3、Foo().getName();  -------- 1
 * 
 * 此处考察了两个知识点，一个是变量作用域问题，一个是this指向问题。
 * 
 * 先执行了Foo函数，然后调用Foo函数的返回值对象的getName属性函数
 * 
 * Foo函数的第一句  getName = function () { alert (1); };  是一句函数赋值语句，注意它没有var声明，
 * 
 * 所以先向当前Foo函数作用域内寻找getName变量，没有。再向当前函数作用域上层，即外层作用域内寻找是否含有getName变量，
 * 
 * 找到了，也就是第二问中的alert(4)函数，将此变量的值赋值为 function(){alert(1)}。 
 * 
 * 此处实际上是将外层作用域内的getName函数修改了。
 * 
 * 简单的讲，this的指向是由所在函数的调用方式决定的。而此处的直接调用方式，this指向window对象。
 * 
 * 遂Foo函数返回的是window对象，相当于执行 window.getName() ，而window中的getName已经被修改为alert(1)，所以最终会输出1
 * 
 * 
 * 4、getName();  ----------- 1
 * 
 * 直接调用getName函数，相当于 window.getName() ，因为这个变量已经被Foo函数执行时修改了，遂结果与第三问相同，为1
 * 
 * 5、new Foo.getName();  --------- 2
 * 
 * 此处考察的是js的运算符优先级问题。
 * 
 * ![JS运算符优先级](https://images2015.cnblogs.com/blog/746158/201602/746158-20160214172949325-418813184.png)
 * 
 * 6、new Foo().getName() -------- 3
 * 
 * 首先看运算符优先级括号高于new，实际执行为：(new Foo()).getName()
 * 
 * 原题中，返回的是this，而this在构造函数中本来就代表当前实例化对象，遂最终Foo函数返回实例化对象。
 * 
 * 之后调用实例化对象的getName函数，因为在Foo构造函数中没有为实例化对象添加任何属性，遂到当前对象的原型对象（prototype）中寻找getName，遂最终输出3。
 * 
 * 
 * 7、new new Foo().getName();; --------- 3
 * 
 * 实际执行为：new ((new Foo()).getName)();
 * 
 * 先初始化Foo的实例化对象，然后将其原型上的getName函数作为构造函数再次new。遂最终结果为3
 * 
 */